using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Navigation;
using Lib.Approval;
using Lib.Helper;
using MSIACCSL2.ApplicationStateServices;
using MSIACCSL2.Command;
using MSIACCSL2.CostCenterServices;
using MSIACCSL2.CurrencyServices;
using MSIACCSL2.CustomerServices;
using MSIACCSL2.DeliveryOrderServices;
using MSIACCSL2.InventoryServices;
using MSIACCSL2.ItemServices;
using MSIACCSL2.SalesInvoiceServices;
using MSIACCSL2.SalesmanServices;
using MSIACCSL2.Views.SalesInvoice;
using WcfService1.DTO;
using DeleteDetailCompletedEventArgs = MSIACCSL2.SalesInvoiceServices.DeleteDetailCompletedEventArgs;
using GetListByCriteriaCompletedEventArgs = MSIACCSL2.SalesInvoiceServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = MSIACCSL2.SalesInvoiceServices.GetListCompletedEventArgs;
using SaveCompletedEventArgs = MSIACCSL2.SalesInvoiceServices.SaveCompletedEventArgs;


namespace MSIACCSL2.ViewModels
{
    public class SalesInvoiceViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static Search frmSearch;
        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        public static Completed OnSearchCompleted;
        private static NavigationService _NavigationService;
        private readonly AplicationStateServicesClient ApplicationService;
        private readonly CostCenterServicesClient CostCenterClient;
        private readonly CurrencyServicesClient CurrencyClient;
        private readonly CustomerServicesClient CustomerClient;
        private readonly DeliveryOrderServicesClient DeliveryOrderClient;
        private readonly SalesmanServicesClient SalesmanClient;
        private readonly SalesInvoiceServicesClient client;
        private readonly ValidationHandler validationHandler;
        private int CurrentPage;
        private bool IsUsed;
        private ObservableCollection<int> Pages;
        private ObservableCollection<CostCenterDTO> _CostCenters;
        private ObservableCollection<CurrencyDTO> _Currencys;
        private Visibility _CustomerVisibility;
        private ObservableCollection<CustomerDTO> _Customers;
        private ObservableCollection<DeliveryOrderDTO> _DeliveryOrders;
        private bool _IsBusy;
        private bool _IsEnabled;
        private SalesInvoiceDTO _SalesInvoice;
        private PagedCollectionView _SalesInvoices;
        private ObservableCollection<EmployeeDTO> _Salesmans;
        private List<string> _errors;
        private Visibility _messageVisibility;
        private PagedCollectionView _pageSources;
        private Dictionary<string, object> criteria;
        private string expression;
        private bool _EnabledSINo;

        public SalesInvoiceViewModel()
        {
            IsEnabled = true;
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new SalesInvoiceServicesClient();
                CurrencyClient = new CurrencyServicesClient();
                CustomerClient = new CustomerServicesClient();
                DeliveryOrderClient = new DeliveryOrderServicesClient();
                CostCenterClient = new CostCenterServicesClient();
                SalesmanClient = new SalesmanServicesClient();

                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SaveSalesInvoice, CanSave);
                New = new DelegateCommand(NewSalesInvoice, CanNew);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchSalesInvoice, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                CancelCommand = new DelegateCommand(Cancel, CanCancelCommand);
                LoadDOCommand = new DelegateCommand(LoadDeliveryOrder, CanLoadDOCommand);
                validationHandler = new ValidationHandler();
                MessageVisibility = Visibility.Collapsed;
                CustomerVisibility = Visibility.Collapsed;
                ApplicationService = new AplicationStateServicesClient();

                if (mode == Mode.Edit)
                {
                    PrepareEdit();
                    EnabledSINo = false;
                }
                else if (mode == Mode.Search)
                {
                    SalesInvoice = new SalesInvoiceDTO();
                    SalesInvoice.InvoiceDate = null;
                    GetCurrencyList();
                    GetCustomerList();
                    
                }
                else if (mode == Mode.Add)
                {
                    PrepareAdd();
                    EnabledSINo = true;
                }
                else
                {
                    GetList(1, null);
                }
            }
        }


        public ObservableCollection<CostCenterDTO> CostCenters
        {
            get { return _CostCenters; }
            private set
            {
                if (CostCenters == value) return;
                _CostCenters = value;
                FirePropertyChanged("CostCenters");
            }
        }


        public PagedCollectionView SalesInvoices
        {
            get { return _SalesInvoices; }

            private set
            {
                if (SalesInvoices == value) return;
                _SalesInvoices = value;
                int i = (CurrentPage*30);
                foreach (object SalesInvoice in SalesInvoices)
                {
                    i += 1;

                    ((SalesInvoiceDTO) SalesInvoice).No = i;
                }
                FirePropertyChanged("SalesInvoices");
                SalesInvoices.CollectionChanged += SalesInvoice_CollectionChanged;
            }
        }

        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }


        public ObservableCollection<CurrencyDTO> Currencys
        {
            get { return _Currencys; }
            private set
            {
                if (Currencys == value) return;
                _Currencys = value;
                FirePropertyChanged("Currencys");
            }
        }


        public ObservableCollection<CustomerDTO> Customers
        {
            get { return _Customers; }
            private set
            {
                if (Customers == value) return;
                _Customers = value;
                FirePropertyChanged("Customers");
            }
        }


        public ObservableCollection<DeliveryOrderDTO> DeliveryOrders
        {
            get { return _DeliveryOrders; }
            internal set
            {
                if (DeliveryOrders == value) return;
                _DeliveryOrders = value;
                FirePropertyChanged("DeliveryOrders");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }

        public Visibility CustomerVisibility
        {
            get { return _CustomerVisibility; }
            internal set
            {
                _CustomerVisibility = value;
                FirePropertyChanged("CustomerVisibility");
            }
        }

        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public SalesInvoiceDTO SalesInvoice
        {
            get { return _SalesInvoice; }
            private set
            {
                if (SalesInvoice == value) return;
                _SalesInvoice = value;
                FirePropertyChanged("SalesInvoice");
            }
        }

        public ObservableCollection<EmployeeDTO> Salesmans
        {
            get { return _Salesmans; }
            private set
            {
                if (Salesmans == value) return;
                _Salesmans = value;
                FirePropertyChanged("Salesmans");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }
        public ICommand CancelCommand { get; set; }

        public List<string> Errors
        {
            get { return _errors; }
            private set
            {
                if (Errors == value) return;
                _errors = value;
                FirePropertyChanged("Errors");
            }
        }

        public Visibility MessageVisibility
        {
            get { return _messageVisibility; }
            private set
            {
                if (MessageVisibility == value) return;
                _messageVisibility = value;
                FirePropertyChanged("MessageVisibility");
            }
        }

        public bool IsEnabled
        {
            get { return _IsEnabled; }
            internal set
            {
                _IsEnabled = value;
                FirePropertyChanged("IsEnabled");
            }
        }

        public bool EnabledSINo
        {
            get { return _EnabledSINo; }
            internal set
            {
                _EnabledSINo = value;
                FirePropertyChanged("EnabledSINo");
            }
        }

        public ICommand LoadDOCommand { get; set; }

        private void PrepareEdit()
        {
            IsBusy = true;
            SalesInvoice = (SalesInvoiceDTO) Navigation.Args;
            GetSalesInvoice(SalesInvoice.SINo);
            CekTransaksi();
        }


        private void PrepareAdd()
        {
            GetCurrencyList();
            GetSalesmanList(Mode.Add);
            GetCostCenterList();

            SalesInvoice = new SalesInvoiceDTO();
            SalesInvoice.SalesInvoiceDetails = new ObservableCollection<SalesInvoiceDetailDTO>();
            var SalesInvoiceDetail = new SalesInvoiceDetailDTO();
            SalesInvoiceDetail.Inventory = new InventoryDTO();
            SalesInvoice.SalesInvoiceDetails.Add(SalesInvoiceDetail);
            SalesInvoiceDetail.DiscountType = "%";
            //CekTransaksi();
        }


        public void GetSalesInvoice(string SINo)
        {
            client.GetSalesInvoiceCompleted += client_GetSalesInvoiceCompleted;
            client.GetSalesInvoiceAsync(SINo);
        }

        private void client_GetSalesInvoiceCompleted(object sender, GetSalesInvoiceCompletedEventArgs e)
        {
            client.GetSalesInvoiceCompleted -= client_GetSalesInvoiceCompleted;
            SalesInvoice = e.Result;
            if (SalesInvoice.SalesInvoiceDetails == null)
                SalesInvoice.SalesInvoiceDetails = new ObservableCollection<SalesInvoiceDetailDTO>();
            if (SalesInvoice.SalesInvoiceDetails.Count == 0)
                SalesInvoice.SalesInvoiceDetails.Add(new SalesInvoiceDetailDTO());

            GetCurrencyList();
            GetSalesmanList(Mode.Edit);
            //GetDeliveryOrderList(SalesInvoice.CostCenter);
            GetCostCenterList();

            IsBusy = false;
        }

        public void GetSalesInvoice2(string SINo)
        {
            client.GetSalesInvoiceCompleted += client_GetSalesInvoiceCompleted2;
            client.GetSalesInvoiceAsync(SINo);
        }

        private void client_GetSalesInvoiceCompleted2(object sender, GetSalesInvoiceCompletedEventArgs e)
        {
            client.GetSalesInvoiceCompleted -= client_GetSalesInvoiceCompleted2;
            if (e.Result != null && !string.IsNullOrEmpty(e.Result.SINo))
                Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("Nomer SI sudah ada!"));
        }

        private void GetCostCenterList()
        {
            CostCenterClient.GetAllCostCenterCompleted += CostCenterClient_GetAllCostCenterCompleted;
            CostCenterClient.GetAllCostCenterAsync();
        }

        private void CostCenterClient_GetAllCostCenterCompleted(object sender, GetAllCostCenterCompletedEventArgs e)
        {
            CostCenterClient.GetAllCostCenterCompleted -= CostCenterClient_GetAllCostCenterCompleted;
            CostCenters = e.Result;
            if (SalesInvoice != null)
                if (SalesInvoice.CostCenter != null)
                    SalesInvoice.CostCenter =
                        CostCenters.FirstOrDefault(x => x.CostCenterId == SalesInvoice.CostCenter.CostCenterId);
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void SalesInvoice_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SaveSalesInvoice(Object salesInvoice)
        {
            //SalesInvoice = (SalesInvoiceDTO) salesInvoice;
            if (SalesInvoice.SalesInvoiceDetails.Count == 1)
            {
                //Bila tidak ada yang dipilih di detail maka details harus dihapus
                if (SalesInvoice.SalesInvoiceDetails[0].Inventory == null)
                    SalesInvoice.SalesInvoiceDetails.Clear();
            }
            Validate();
            if (Errors.Count > 0) return;
            SalesInvoice.created_by = GlobalVar.User.UserID;
            SalesInvoice.modified_by = GlobalVar.User.UserID;
            IsBusy = true;
            client.SaveCompleted += client_SaveCompleted;
            bool isNew = false ;
            if (mode != Mode.Edit) isNew = true;

            client.SaveAsync(SalesInvoice,isNew, mode);
        }

        private void client_SaveCompleted(object sender, SaveCompletedEventArgs e)
        {
            if (e.Error != null) Validate(e.Error.ToString());
            client.SaveCompleted -= client_SaveCompleted;
            mode = (Mode) e.UserState;

            if (e.Error!=null)
            {
                MessageBox.Show(e.Error.Message);
                return;
            }

            if (e.Result)
            {
                IsBusy = false;
                ClearTransaksi(mode);
                mode = Mode.Idle;
                Navigation.MyNavigation.Navigate(new Uri("/SalesInvoice/Index", UriKind.Relative));
            }
            else
            {
                IsBusy = false;
                MessageBox.Show("Simpan Gagal, Periksa data Anda!");
            }
        }


        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListCompleted += client_GetListCompleted;
            client.GetListAsync(page ?? 1, sortProp, OrderType);
        }

        private void client_GetListCompleted(object sender, GetListCompletedEventArgs e)
        {
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            client.GetListCompleted -= client_GetListCompleted;
            SalesInvoices = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }


        private void NewSalesInvoice(Object param)
        {
            mode = Mode.Add;
            Navigation.MyNavigation = (NavigationService) param;
            Navigation.MyNavigation.Navigate(new Uri("/SalesInvoice/frmAdd", UriKind.Relative));
        }


        private void SearchSalesInvoice(Object param)
        {
            mode = Mode.Search;
            frmSearch = new Search();
            frmSearch.Show();
        }


        private void SearchResult(Object param)
        {
             criteria = new Dictionary<string, object>();

            foreach (PropertyInfo prop in SalesInvoice.GetType().GetProperties())
            {
                if (prop.PropertyType == typeof (Decimal))
                {
                    if ((Decimal) prop.GetValue(SalesInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int32))
                {
                    if ((Int32) prop.GetValue(SalesInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int64))
                {
                    if ((Int64) prop.GetValue(SalesInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Double))
                {
                    if ((Double) prop.GetValue(SalesInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (String))
                {
                    if (String.IsNullOrEmpty((String) prop.GetValue(SalesInvoice, null))) continue;
                }
                if (prop.PropertyType == typeof (DateTime))
                {
                    if (prop.GetValue(SalesInvoice, null).ToString().Contains("0001")) continue;
                }
                if (prop.GetValue(SalesInvoice, null) == null) continue;
                if (prop.PropertyType.Name == "No") continue;

                if (prop.PropertyType.Name.ToLower().Contains("dto"))
                {
                    foreach (PropertyInfo propertyInfo in prop.GetValue(SalesInvoice, null).GetType().GetProperties()
                        )
                    {
                        if (propertyInfo.Name.ToLower().Contains("id") || propertyInfo.Name.ToLower().Contains("kode") ||
                            propertyInfo.Name.ToLower().Contains("serial") ||
                            propertyInfo.Name.ToLower().Contains("code"))
                        {
                            criteria.Add(prop.Name, propertyInfo.GetValue(prop.GetValue(SalesInvoice, null), null));
                            break;
                        }
                    }
                }
                else
                {
                    criteria.Add(prop.Name, prop.GetValue(SalesInvoice, null));
                }
            }

            expression = string.Empty;
            if (frmSearch.rblOr.IsChecked ?? false) expression = "OR";
            else expression = "AND";
            SalesInvoiceSearch(criteria, expression,1);
        }

        private void SalesInvoiceSearch(Dictionary<String, Object> criteria, string expression,int page)
        {
            if (criteria.ContainsKey("Status")) criteria.Remove("Status");
            frmSearch.DialogResult = true;
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, page);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            client.GetListByCriteriaCompleted -= client_GetListByCriteriaCompleted;
            SalesInvoices = new PagedCollectionView(e.Result);
            if (RecordCount != e.recordCount)
            {
                RecordCount = e.recordCount;
                CreatePageNumber();
            }
            IsBusy = false;
        }


        private void GetCurrencyList()
        {
            CurrencyClient.GetAllCurrencyCompleted += CurrencyClient_GetAllCurrencyCompleted;
            CurrencyClient.GetAllCurrencyAsync(mode);
        }

        private void CurrencyClient_GetAllCurrencyCompleted(object sender, GetAllCurrencyCompletedEventArgs e)
        {
            CurrencyClient.GetAllCurrencyCompleted -= CurrencyClient_GetAllCurrencyCompleted;
            Currencys = e.Result;
            Currencys.Insert(0,new CurrencyDTO());
            mode = (Mode) e.UserState;
            if (mode == Mode.Add)
            {
                SalesInvoice.Currency = Currencys.FirstOrDefault(x => x.CurrencyCode == "Rp");
                SalesInvoice.Rate = 1;
            }
         

            if (SalesInvoice != null)
            {
                if (SalesInvoice.Currency == null) return;
                SalesInvoice.Currency =
                    Currencys.FirstOrDefault(s => s.CurrencyCode == SalesInvoice.Currency.CurrencyCode);
            }
        }

        private void GetCustomerList()
        {
            CustomerClient.GetAllCustomerCompleted += CustomerClient_GetAllCustomerCompleted;
            CustomerClient.GetAllCustomerAsync();
        }

        private void CustomerClient_GetAllCustomerCompleted(object sender, GetAllCustomerCompletedEventArgs e)
        {
            CustomerClient.GetAllCustomerCompleted -= CustomerClient_GetAllCustomerCompleted;
            Customers = e.Result;

            if (SalesInvoice != null)
            {
                if (SalesInvoice.Customer == null) return;
                SalesInvoice.Customer =
                    Customers.FirstOrDefault(s => s.CustomerId == SalesInvoice.Customer.CustomerId);
            }
        }

        public void GetDeliveryOrderList(Object param)
        {
            if (param == null) return;
            DeliveryOrderClient.GetAllDeliveryOrderByCostCenterCompleted +=
                DeliveryOrderClient_GetAllDeliveryOrderByCostCenterCompleted;
            DeliveryOrderClient.GetAllDeliveryOrderByCostCenterAsync(param as CostCenterDTO);
        }

        private void DeliveryOrderClient_GetAllDeliveryOrderByCostCenterCompleted(object sender,
                                                                                  GetAllDeliveryOrderByCostCenterCompletedEventArgs
                                                                                      e)
        {
            DeliveryOrderClient.GetAllDeliveryOrderByCostCenterCompleted -=
                DeliveryOrderClient_GetAllDeliveryOrderByCostCenterCompleted;
            DeliveryOrders = new ObservableCollection<DeliveryOrderDTO>(e.Result.Where(d=>d.DODate <= SalesInvoice.InvoiceDate));

            //Mapping DO Detail
            foreach (DeliveryOrderDTO DeliveryOrder in DeliveryOrders)
            {
                DeliveryOrder.DeliveryOrderDetails = new ObservableCollection<DeliveryOrderDetailDTO>();
                DeliveryOrderDTO PO = e.Result.FirstOrDefault(x => x.DONo == DeliveryOrder.DONo);
                foreach (DeliveryOrderDetailDTO DODetail in PO.DeliveryOrderDetails)
                    DeliveryOrder.DeliveryOrderDetails.Add(
                        DODetail);
            }

            //Edit Mode
            if (SalesInvoice != null)
            {
                if (SalesInvoice.DeliveryOrder != null)
                {
                    DeliveryOrders.Add(SalesInvoice.DeliveryOrder);
                    SalesInvoice.RaisePropertyChanged("DeliveryOrder");
                }
            }
        }


        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            SalesInvoice = null;
            if (SalesInvoices != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (mode == Mode.Search)
                    SalesInvoiceSearch(criteria, expression, (int)pageIndex + 1);
                else if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }

        public bool CanCancelCommand(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            SalesInvoice = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (SalesInvoices == null)
                GetList(1, null);
            else
                Complete(this);
        }


        public void Validate(string error = null)
        {
            Errors = new List<string>();
            if (string.IsNullOrEmpty(SalesInvoice.SINo))
                Errors.Add("Nomor SI tidak boleh kosong");
            if (SalesInvoice.SINo.Length < 14)
                Errors.Add("Nomor SI belum lengkap");
            if (SalesInvoice.Customer == null)
                Errors.Add("Customer harus diisi!");
            if (SalesInvoice.DeliveryOrder == null)
                Errors.Add("DO belum dipilih!");
            if (SalesInvoice.Salesman == null)
                Errors.Add("Salesman tidak boleh kosong!");
            if (SalesInvoice.CostCenter == null)
                Errors.Add("CostCenter tidak boleh kosong!");
            if (SalesInvoice.Currency == null)
                Errors.Add("Currency tidak boleh kosong!");
            
            foreach (SalesInvoiceDetailDTO SIDetail in SalesInvoice.SalesInvoiceDetails)
              if (SIDetail.Qty == 0)
                    Errors.Add("Serial Number " + SIDetail.Inventory.SerialNumber + " Qtynya tidak boleh 0!");


            if (!string.IsNullOrEmpty(error))
                Errors.Add(error);

            MessageVisibility = Errors.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
        }

      

        public void Cancel(Object param)
        {
            MessageBoxResult res = MessageBox.Show("Are You Sure Want to Cancel ?", "Confirmation",
                                                   MessageBoxButton.OKCancel);
            if (res == MessageBoxResult.OK)
            {
                if (!IsUsed) ClearTransaksi(mode);
                mode = Mode.Idle;
                Navigation.MyNavigation.GoBack();
            }
        }

        public void GetLastNoSalesInvoice(Object param)
        {
            if (param == null) return;
            client.GetLastSINoCompleted += client_GetLastSINoCompleted;
            client.GetLastSINoAsync(param as CostCenterDTO, (param as CostCenterDTO).CostCenterId);
        }

        private void client_GetLastSINoCompleted(object sender, GetLastSINoCompletedEventArgs e)
        {
            client.GetLastSINoCompleted -= client_GetLastSINoCompleted;
            string res = e.Result;
            string formatSO = "0000";
            string kodeSO;
            if (e.Result.Length <= 4)
            {
                res = formatSO;
                kodeSO = e.Result;
            }
            else
            {
                res = e.Result.Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries)[3];
                kodeSO = e.Result.Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries)[0];
            }
            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(res) + 1).ToString().Length) +
                           (int.Parse(res) + 1);

            string costCenter = e.UserState.ToString();
            SalesInvoice.SINo = kodeSO + "/" + costCenter + "/" + DateTime.Now.Year + "/";//+ soNum;
        }


        private void AddSalesInvoiceDetail()
        {
            SalesInvoice.SalesInvoiceDetails.Add(new SalesInvoiceDetailDTO());
        }

        public bool CanLoadDOCommand(Object param)
        {
            return true;
        }

        public void LoadDeliveryOrder(Object param)
        {
            if (param == null) return;
            var deliveryOrder = (DeliveryOrderDTO) param;
            DeliveryOrderClient.GetDeliveryOrderCompleted += DeliveryOrderClient_GetDeliveryOrderCompleted;
            DeliveryOrderClient.GetDeliveryOrderAsync(deliveryOrder.DONo);
        }

        private void DeliveryOrderClient_GetDeliveryOrderCompleted(object sender, GetDeliveryOrderCompletedEventArgs e)
        {
            DeliveryOrderClient.GetDeliveryOrderCompleted -= DeliveryOrderClient_GetDeliveryOrderCompleted;
            if (e.Result.SalesOrder != null)
            {
                if (e.Result.SalesOrder.Currency != null)
                    foreach (
                        CurrencyDTO currencyDto in
                            Currencys.Where(c => c.CurrencyCode == e.Result.SalesOrder.Currency.CurrencyCode))
                        SalesInvoice.Currency = currencyDto;

                SalesInvoice.Rate = e.Result.SalesOrder.Rate;
                SalesInvoice.Term = e.Result.SalesOrder.Term;
                SalesInvoice.IsPpn = e.Result.SalesOrder.Ppn != 0;
                SalesInvoice.Salesman =
                    Salesmans.FirstOrDefault(x => x.KodeSalesman == e.Result.SalesOrder.Salesman.KodeSalesman);
                SalesInvoice.Discount = e.Result.SalesOrder.Discount;
                SalesInvoice.DiscountType = e.Result.SalesOrder.DiscountType;

            }

            if (e.Result.Spk != null)
            {
                if (e.Result.Spk.Currency != null)
                    foreach (
                        CurrencyDTO currencyDto in
                            Currencys.Where(c => c.CurrencyCode == e.Result.Spk.Currency.CurrencyCode))
                        SalesInvoice.Currency = currencyDto;

                SalesInvoice.Rate = e.Result.Spk.Rate;
                //SalesInvoice.Term = e.Result.Spk.Term;
                SalesInvoice.IsPpn = e.Result.Spk.Ppn != 0;
                SalesInvoice.Discount = e.Result.SalesOrder.Discount;
                SalesInvoice.DiscountType = e.Result.SalesOrder.DiscountType;
            }

            SalesInvoice.DeliveryOrder = e.Result;

            SalesInvoice.SalesInvoiceDetails.Clear();
            //Tarik SerialNumber
            foreach (
                DeliveryOrderDetailDTO deliveryOrderDetail in
                    e.Result.DeliveryOrderDetails)
            {
                var siDetail = new SalesInvoiceDetailDTO();
                siDetail.Inventory =
                    deliveryOrderDetail.Inventory;
                siDetail.Qty = deliveryOrderDetail.QtyUnit;
                siDetail.Sheet = deliveryOrderDetail.Tinggi;
                siDetail.Panjang = deliveryOrderDetail.Panjang;
                siDetail.Lebar = deliveryOrderDetail.Lebar;
                SalesInvoice.SalesInvoiceDetails.Add(siDetail);
            }

            //tarik harga
            if (e.Result.SalesOrder != null)
                if (e.Result.SalesOrder.Type == "Inventory")
                    foreach (SalesOrderDetailDTO salesOrderDetail in e.Result.SalesOrder.SalesOrderDetails)
                    {
                        if (salesOrderDetail.Inventory != null)
                        {
                            SalesInvoiceDetailDTO siDetail = SalesInvoice.SalesInvoiceDetails.FirstOrDefault(
                                x => x.Inventory.SerialNumber == salesOrderDetail.Inventory.SerialNumber);

                            if (siDetail != null)
                            {
                                siDetail.Price =
                                    salesOrderDetail.Price;
                                siDetail.Discount =
                                    salesOrderDetail.Discount;
                                siDetail.DiscountType =
                                    salesOrderDetail.DiscountType;
                                if (salesOrderDetail.DiscountType != "%")
                                    siDetail.TotalDetail = (siDetail.Price*siDetail.Qty) - siDetail.Discount;
                                else
                                    siDetail.TotalDetail = (siDetail.Price*siDetail.Qty) -
                                                           ((siDetail.Price*siDetail.Qty)*siDetail.Discount/100);
                            }
                        }
                    }

            if (e.Result.Spk != null)
                if (e.Result.Spk.Type == "Inventory")
                    foreach (SpkDetailDTO spkDetail in e.Result.Spk.SpkDetails)
                    {
                        SalesInvoiceDetailDTO siDetail = SalesInvoice.SalesInvoiceDetails.FirstOrDefault(
                            x => x.Inventory.SerialNumber == spkDetail.Inventory.SerialNumber);

                        siDetail.Price =
                            spkDetail.Price;
                        siDetail.Discount =
                            spkDetail.Discount;
                        siDetail.DiscountType =
                            spkDetail.DiscountType;
                        if (spkDetail.DiscountType != "%")
                            siDetail.TotalDetail = (siDetail.Price*siDetail.Qty) - siDetail.Discount;
                        else
                            siDetail.TotalDetail = (siDetail.Price*siDetail.Qty) -
                                                   ((siDetail.Price*siDetail.Qty)*siDetail.Discount/100);
                    }

           
        }

        public void GetCustomer(Object param)
        {
            CustomerClient.GetCustomerListCompleted += CustomerClient_GetCustomerListCompleted;
            CustomerClient.GetCustomerListAsync(param.ToString());
        }

        private void CustomerClient_GetCustomerListCompleted(object sender, GetCustomerListCompletedEventArgs e)
        {
            CustomerClient.GetCustomerListCompleted -= CustomerClient_GetCustomerListCompleted;
            Customers = e.Result;
            CustomerVisibility = Visibility.Visible;
            EventAggregator.PublishMessage("CustomerSelect", string.Empty);
        }

        public void GetSalesmanList(Mode mode)
        {
            SalesmanClient.GetAllSalesmanCompleted += SalesmanClient_GetAllSalesmanCompleted;
            SalesmanClient.GetAllSalesmanAsync(mode);
        }

        private void SalesmanClient_GetAllSalesmanCompleted(object sender, GetAllSalesmanCompletedEventArgs e)
        {
            SalesmanClient.GetAllSalesmanCompleted -= SalesmanClient_GetAllSalesmanCompleted;
            Salesmans = e.Result;
            var mode = (Mode) e.UserState;
            if (mode == Mode.Edit)
            {
                if (SalesInvoice.Salesman != null)
                    SalesInvoice.Salesman =
                        Salesmans.FirstOrDefault(x => x.KodeSalesman == SalesInvoice.Salesman.KodeSalesman);
            }
        }


        public void CustomerSelected(Object param)
        {
            SalesInvoice.Customer = ((CustomerDTO) param);
            CustomerVisibility = Visibility.Collapsed;
        }

        public void Print(Object param)
        {
            Navigation.MyNavigation.Navigate(new Uri("/SalesInvoice/PrintPreviewSI", UriKind.Relative));
            Navigation.Args = param;
        }

        public void CekTransaksi()
        {
            ApplicationService.IsTransactionUsedCompleted += ApplicationService_IsTransactionUsedCompleted;
            if (string.IsNullOrEmpty(SalesInvoice.SINo))
            {
                ApplicationService.IsTransactionUsedAsync(SalesInvoice.ToString(), GlobalVar.User, mode);
                GlobalVar.CurrentTransaction = SalesInvoice.ToString();
            }
            else
            {
                ApplicationService.IsTransactionUsedAsync(SalesInvoice.SINo, GlobalVar.User, mode);
                GlobalVar.CurrentTransaction = SalesInvoice.SINo;
            }
        }

        private void ApplicationService_IsTransactionUsedCompleted(object sender, IsTransactionUsedCompletedEventArgs e)
        {
            ApplicationService.IsTransactionUsedCompleted -= ApplicationService_IsTransactionUsedCompleted;
            IsUsed = e.Result;
            mode = (Mode) e.UserState;
            if (IsUsed)
            {
                MessageBox.Show("Transaksi sedang digunakan!");
                if (mode == Mode.Add) //If Add Mode
                {
                    mode = Mode.Idle;
                    Navigation.MyNavigation.Navigate(new Uri("/SalesInvoice/Index", UriKind.Relative));
                }
                else //Edit Mode just view Only
                {
                    IsEnabled = false;
                }
            }
        }

        private void ClearTransaksi(Mode mode)
        {
            ApplicationService.ClearTransactionCompleted += ApplicationService_ClearTransactionCompleted;
            if (mode == Mode.Add)
                ApplicationService.ClearTransactionAsync(SalesInvoice.ToString(), GlobalVar.User);
            else
                ApplicationService.ClearTransactionAsync(SalesInvoice.SINo, GlobalVar.User);
        }

        private void ApplicationService_ClearTransactionCompleted(object sender, AsyncCompletedEventArgs e)
        {
            ApplicationService.ClearTransactionCompleted -= ApplicationService_ClearTransactionCompleted;
        }

        public void CloseStatus()
        {
            MessageBoxResult res = MessageBox.Show("Are You Sure Want to Close this Transaction ?", "Confirmation",
                                                MessageBoxButton.OKCancel);
            if (res == MessageBoxResult.OK)
            {
                client.UpdateStatusCompleted += new EventHandler<AsyncCompletedEventArgs>(client_UpdateStatusCompleted);
                client.UpdateStatusAsync(SalesInvoice, Status.Close);
            }
        }

        void client_UpdateStatusCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.UpdateStatusCompleted -= new EventHandler<AsyncCompletedEventArgs>(client_UpdateStatusCompleted);
            MessageBox.Show("Update Status finished!");
        }
    }


    public class SalesInvoiceWrapViewModel : ViewModelBase
    {
        private readonly InventoryServiceClient InventoryClient;
        private readonly ItemServicesClient ItemClient;
        private readonly SalesInvoiceServicesClient client;
        private List<string> _DiscTypes;
        private ObservableCollection<InventoryDTO> _Inventorys;
        private SalesInvoiceDetailDTO _SalesInvoiceDetail;

        public SalesInvoiceWrapViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new SalesInvoiceServicesClient();
                InventoryClient = new InventoryServiceClient();

                EditCommand = new DelegateCommand(Edit, CanEditCommand);
                DeleteCommand = new DelegateCommand(Delete, CanDeleteCommand);
                AddDetailCommand = new DelegateCommand(AddSalesInvoiceDetail, CanAddDetailCommand);
                DeleteDetailCommand = new DelegateCommand(DeleteSalesInvoiceDetail, CanDeleteDetailCommand);
                GetTotalDetailCommand = new DelegateCommand(GetTotalDetail, CanGetTotalDetailCommand);
                GetPpnCommand = new DelegateCommand(GetPpn, CanGetPpnCommand);
                GetInventoryCommand = new DelegateCommand(GetInventory, CanGetInventoryCommand);
                GetTotalDiscountCommand = new DelegateCommand(GetTotalDiscount, CanGetTotalDiscount);
                GetQtyUnitCommand = new DelegateCommand(GetQtyUnit, CanGetQtyUnit);

                DiscTypes = new List<string>();
                DiscTypes.Add("%");
                DiscTypes.Add("val");
                if (SalesInvoiceViewModel.mode == Mode.Add || SalesInvoiceViewModel.mode == Mode.Edit)
                {
                }
            }
        }

        public SalesInvoiceViewModel SalesInvoiceViewModel { get; set; }


        public ICommand EditCommand { get; set; }
        public ICommand DeleteCommand { get; set; }
        public ICommand AddDetailCommand { get; set; }
        public ICommand DeleteDetailCommand { get; set; }
     


        public ObservableCollection<InventoryDTO> Inventorys
        {
            get { return _Inventorys; }
            private set
            {
                if (Inventorys == value) return;
                _Inventorys = value;
                FirePropertyChanged("Inventorys");
            }
        }

        public List<string> DiscTypes
        {
            get { return _DiscTypes; }
            private set
            {
                if (DiscTypes == value) return;
                _DiscTypes = value;
                FirePropertyChanged("DiscTypes");
            }
        }


        public SalesInvoiceDetailDTO SalesInvoiceDetail
        {
            get { return _SalesInvoiceDetail; }
            private set
            {
                if (SalesInvoiceDetail == value) return;
                _SalesInvoiceDetail = value;
                FirePropertyChanged("SalesInvoiceDetail");
            }
        }

        public ICommand GetInventoryCommand { get; set; }
        public ICommand GetQtyUnitCommand { get; set; }
        public ICommand GetTotalDetailCommand { get; set; }
        public ICommand GetPpnCommand { get; set; }
        public ICommand GetTotalDiscountCommand { get; set; }

        public bool CanEditCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteCommand(Object param)
        {
            return true;
        }

        public bool CanAddDetailCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteDetailCommand(Object param)
        {
            return true;
        }


        public void Edit(Object param)
        {
            SalesInvoiceViewModel.mode = Mode.Edit;
            Navigation.MyNavigation.Navigate(new Uri("/SalesInvoice/frmAdd", UriKind.Relative));
            Navigation.Args = param;
        }

        public void Delete(Object param)
        {
            DeleteConfirmation deleteConfirmation = new DeleteConfirmation();
            deleteConfirmation.Show();
            EventAggregator.RegisterMessage("ApprovalSucceeded", (x) =>
            {
                deleteConfirmation.Close();
                client.DeleteCompleted += client_DeleteCompleted;
                client.DeleteAsync((SalesInvoiceDTO)param);
            });

        }

        private void client_DeleteCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.DeleteCompleted -= client_DeleteCompleted;
            MessageBox.Show("Delete Success!");
            SalesInvoiceViewModel.mode = Mode.Idle;
            var VM = new SalesInvoiceViewModel();
        }


        public void GetInventory(Object param)
        {
            SalesInvoiceDetail = (SalesInvoiceDetailDTO) param;
            if (SalesInvoiceDetail.Inventory == null) SalesInvoiceDetail.Inventory = new InventoryDTO();
            string SerialNumber = SalesInvoiceDetail.Inventory.SerialNumber;
            InventoryClient.GetInventoryCompleted +=
                InventoryClient_GetInventoryCompleted;
            InventoryClient.GetInventoryAsync(SerialNumber);
        }

        private void InventoryClient_GetInventoryCompleted(object sender, GetInventoryCompletedEventArgs e)
        {
            InventoryClient.GetInventoryCompleted -=
                InventoryClient_GetInventoryCompleted;
            InventoryDTO InventoryTemp = e.Result;

            if (null != InventoryTemp && ! string.IsNullOrEmpty(InventoryTemp.SerialNumber))
            {
                SalesInvoiceDetail.Inventory = InventoryTemp;
                SalesInvoiceDetail.Sheet = InventoryTemp.Warehouses.FirstOrDefault().Sheet;
                SalesInvoiceDetail.Panjang = InventoryTemp.Panjang;
                SalesInvoiceDetail.Lebar = InventoryTemp.Lebar;
                SalesInvoiceDetail.Qty = InventoryTemp.Warehouses.FirstOrDefault().Qty;
                SalesInvoiceDetail.Inventory.Item = e.Result.Item;
                SalesInvoiceDetail.Inventory.SatuanUnit =
                    e.Result.SatuanUnit;
            }else
            {
                MessageBox.Show("Barang tidak ditemukan, coba entry secara manual");
            }
        }

        public void AddSalesInvoiceDetail(Object param)
        {
            SalesInvoiceDetail = new SalesInvoiceDetailDTO();
            SalesInvoiceDetail.Inventory = new InventoryDTO();
            SalesInvoiceViewModel.SalesInvoice.SalesInvoiceDetails.Add(SalesInvoiceDetail);
        }

        public void DeleteSalesInvoiceDetail(Object param)
        {
            var SalesInvoiceDetail = (SalesInvoiceDetailDTO) param;
            if (SalesInvoiceViewModel.SalesInvoice.SalesInvoiceDetails.Count > 1)
            {
                SalesInvoiceViewModel.SalesInvoice.SalesInvoiceDetails.Remove(SalesInvoiceDetail);
                GetTotalDetail(SalesInvoiceDetail);
            }
        }

        public bool CanGetInventoryCommand(Object param)
        {
            return true;
        }

        public bool CanGetQtyUnit(Object param)
        {
            return true;
        }

        public void GetQtyUnit(Object param)
        {
            if (SalesInvoiceDetail.Inventory != null)
            {
                if (SalesInvoiceDetail.Inventory.SatuanUnit != null)
                    SalesInvoiceDetail.Qty = SalesInvoiceDetail.Inventory.QtyPack *
                                             (SalesInvoiceDetail.Panjang *
                                              SalesInvoiceDetail.Lebar *
                                              SalesInvoiceDetail.Sheet) /
                                             SalesInvoiceDetail.Inventory.SatuanUnit.Pengali;

                SalesInvoiceDetail.Qty = SalesInvoiceDetail.Inventory.Item != null && SalesInvoiceDetail.Inventory.Item.IsRounded
                                             ? SalesInvoiceDetail.Qty.Round(2, MidpointRounding.AwayFromZero)
                                             : SalesInvoiceDetail.Qty.Round(4, MidpointRounding.AwayFromZero);

                GetTotalDetail(SalesInvoiceDetail);
            }
        }

        public bool CanGetTotalDetailCommand(Object param)
        {
            return true;
        }

        public void GetTotalDetail(Object param)
        {
            SalesInvoiceDetail = (SalesInvoiceDetailDTO) param;

            if (SalesInvoiceDetail.DiscountType != "%")
                SalesInvoiceDetail.TotalDetail = (SalesInvoiceDetail.Price*SalesInvoiceDetail.Qty) -
                                                 SalesInvoiceDetail.Discount;
            else
                SalesInvoiceDetail.TotalDetail = (SalesInvoiceDetail.Price*SalesInvoiceDetail.Qty) -
                                                 ((SalesInvoiceDetail.Price*SalesInvoiceDetail.Qty)*
                                                  SalesInvoiceDetail.Discount/100);
            SalesInvoiceViewModel.SalesInvoice.SubTotal =
                SalesInvoiceViewModel.SalesInvoice.SalesInvoiceDetails.Sum(p => p.TotalDetail);
            if (SalesInvoiceViewModel.SalesInvoice.DiscountType != "%")
                SalesInvoiceViewModel.SalesInvoice.AfterDiscount = SalesInvoiceViewModel.SalesInvoice.SubTotal -
                                                                   SalesInvoiceViewModel.SalesInvoice.Discount;
            else
                SalesInvoiceViewModel.SalesInvoice.AfterDiscount = SalesInvoiceViewModel.SalesInvoice.SubTotal -
                                                                   (SalesInvoiceViewModel.SalesInvoice.SubTotal*
                                                                    SalesInvoiceViewModel.SalesInvoice.Discount/100);
            if (SalesInvoiceViewModel.SalesInvoice.IsPpn)
                SalesInvoiceViewModel.SalesInvoice.Ppn = SalesInvoiceViewModel.SalesInvoice.AfterDiscount*10/100;
            if (SalesInvoiceViewModel.SalesInvoice.Ppn > 0)
                SalesInvoiceViewModel.SalesInvoice.IsPpn = true;
            SalesInvoiceViewModel.SalesInvoice.Total =
                SalesInvoiceViewModel.SalesInvoice.AfterDiscount + SalesInvoiceViewModel.SalesInvoice.Ppn;
        }


        public bool CanGetPpnCommand(Object param)
        {
            return true;
        }

        public void GetPpn(Object param)
        {
            var SalesInvoice = (SalesInvoiceDTO) param;
            if (SalesInvoice.IsPpn)
            {
                SalesInvoice.Ppn = SalesInvoice.AfterDiscount*10/100;
                SalesInvoice.Total = SalesInvoice.AfterDiscount + SalesInvoice.Ppn;
            }
            else
            {
                SalesInvoice.Ppn = 0;
                SalesInvoice.Total = SalesInvoice.AfterDiscount + SalesInvoice.Ppn;
            }
        }

        public bool CanGetTotalDiscount(Object param)
        {
            return true;
        }

        public void GetTotalDiscount(Object param)
        {
            var SalesInvoice = (SalesInvoiceDTO) param;
            if (SalesInvoice.SalesInvoiceDetails != null)
                SalesInvoice.SubTotal =
                    SalesInvoice.SalesInvoiceDetails.Sum(p => p.TotalDetail);
            if (SalesInvoice.DiscountType != "%")
                SalesInvoice.AfterDiscount = SalesInvoice.SubTotal - SalesInvoice.Discount;
            else
                SalesInvoice.AfterDiscount = SalesInvoice.SubTotal - (SalesInvoice.SubTotal*SalesInvoice.Discount/100);
            if (SalesInvoice.IsPpn)
                SalesInvoice.Ppn = SalesInvoice.AfterDiscount*10/100;
            if (SalesInvoice.Ppn > 0)
                SalesInvoice.IsPpn = true;
            SalesInvoice.Total =
                SalesInvoice.AfterDiscount + SalesInvoice.Ppn;
        }
    }


    public class SalesInvoiceConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null)
            {
                return ((dynamic) value).SINo;
            }
            else
            {
                return string.Empty;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}